{%extends 'layout.admin.html'%}
{%block content%}
{% load authfilters %}

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/codemirror@5.65.2/lib/codemirror.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/codemirror@5.65.2/theme/monokai.css">
<script src="https://cdn.jsdelivr.net/npm/codemirror@5.65.2/lib/codemirror.js"></script>
<script src="https://cdn.jsdelivr.net/npm/codemirror@5.65.2/mode/javascript/javascript.js"></script>

<div class="page-header d-print-none">
  <div class="container-xl">
    <div class="row g-2 align-items-center">
      <div class="col">
        <h1 class="page-title">Free Online JavaScript Compressor & Minifier - Optimize Your JS Code</h1>
      </div>
      <div class="seo-h1">
        <h2>Compress and Minify JavaScript Files Online</h2>
        <h2>Key Features of Our JS Compressor Tool
            <ul>
                <li>Minify JavaScript: Remove unnecessary whitespace, comments, and line breaks to reduce file size.</li>
                <li>Beautify JavaScript: Format minified JS code for better readability and debugging.</li>
                <li>File Upload Support: Upload .js files directly or paste code into the editor.</li>
                <li>Real-time Processing: Instantly see compression results and file size reduction.</li>
                <li>Download Results: Save the compressed JavaScript file to your computer.</li>
                <li>100% Client-Side: Your code never leaves your browser, ensuring privacy and security.</li>
            </ul>
        </h2>
        <h2>How to Use This JavaScript Compressor?
            <ul>
                <li>Upload a .js file or paste your JavaScript code into the editor.</li>
                <li>Choose between Minify (compress) or Beautify (format) options.</li>
                <li>Click the process button to compress or format your code.</li>
                <li>Download the optimized JavaScript file or copy the result.</li>
            </ul>
        </h2>
        <h2>Frequently Asked Questions (FAQs)
            <h3>Why should I minify JavaScript?</h3>
            <h3>Will minification break my JavaScript code?</h3>
            <h3>Is this JavaScript compressor free to use?</h3>
        </h2>
      </div>
    </div>
  </div>
</div>

<style type="text/css">
.js-editor {
    border: 1px solid #dee2e6;
    border-radius: 0.375rem;
}
.CodeMirror {
    height: 400px;
    font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
    font-size: 14px;
}
.file-stats {
    background-color: #f8f9fa;
    border: 1px solid #dee2e6;
    border-radius: 0.375rem;
    padding: 1rem;
    margin-bottom: 1rem;
}
.stats-item {
    display: flex;
    justify-content: space-between;
    margin-bottom: 0.5rem;
}
.stats-item:last-child {
    margin-bottom: 0;
}
.compression-ratio {
    color: #198754;
    font-weight: bold;
}
</style>

<div class="page-body">
    <div class="container-xl">
        <div class="row">
            <div class="col-md-6">
                <div class="card">
                    <div class="card-header">
                        <h3 class="card-title">Input JavaScript</h3>
                        <div class="card-actions">
                            <label class="btn btn-primary">
                                <input type="file" id="js-file-input" accept=".js" style="display: none;">
                                Upload .js File
                            </label>
                        </div>
                    </div>
                    <div class="card-body">
                        <div class="js-editor">
                            <textarea id="input-editor" placeholder="Paste your JavaScript code here or upload a .js file..."></textarea>
                        </div>
                    </div>
                </div>

                <div class="card mt-3">
                    <div class="card-body">
                        <div class="row">
                            <div class="col-auto">
                                <button id="minify-btn" class="btn btn-success">
                                    <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon me-2">
                                        <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path>
                                        <polyline points="7,10 12,15 17,10"></polyline>
                                        <line x1="12" y1="15" x2="12" y2="3"></line>
                                    </svg>
                                    Minify JavaScript
                                </button>
                            </div>
                            <div class="col-auto">
                                <button id="beautify-btn" class="btn btn-info">
                                    <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon me-2">
                                        <polyline points="22,12 18,12 15,21 9,3 6,12 2,12"></polyline>
                                    </svg>
                                    Beautify JavaScript
                                </button>
                            </div>
                            <div class="col-auto">
                                <button id="clear-btn" class="btn btn-secondary">
                                    <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon me-2">
                                        <line x1="18" y1="6" x2="6" y2="18"></line>
                                        <line x1="6" y1="6" x2="18" y2="18"></line>
                                    </svg>
                                    Clear
                                </button>
                            </div>
                        </div>
                    </div>
                </div>
            </div>

            <div class="col-md-6">
                <div class="card">
                    <div class="card-header">
                        <h3 class="card-title">Output JavaScript</h3>
                        <div class="card-actions">
                            <button id="download-btn" class="btn btn-primary" disabled>
                                <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon me-2">
                                    <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path>
                                    <polyline points="7,10 12,15 17,10"></polyline>
                                    <line x1="12" y1="15" x2="12" y2="3"></line>
                                </svg>
                                Download
                            </button>
                            <button id="copy-btn" class="btn btn-secondary ms-2" disabled>
                                <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon me-2">
                                    <rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
                                    <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
                                </svg>
                                Copy
                            </button>
                        </div>
                    </div>
                    <div class="card-body">
                        <div id="file-stats" class="file-stats" style="display: none;">
                            <div class="stats-item">
                                <span>Original Size:</span>
                                <span id="original-size">0 bytes</span>
                            </div>
                            <div class="stats-item">
                                <span>Compressed Size:</span>
                                <span id="compressed-size">0 bytes</span>
                            </div>
                            <div class="stats-item">
                                <span>Compression Ratio:</span>
                                <span id="compression-ratio" class="compression-ratio">0%</span>
                            </div>
                        </div>
                        <div class="js-editor">
                            <textarea id="output-editor" placeholder="Processed JavaScript will appear here..." readonly></textarea>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>

<script type='text/javascript'>
$(document).ready(function() {
    // Initialize CodeMirror editors
    var inputEditor = CodeMirror.fromTextArea(document.getElementById('input-editor'), {
        mode: 'javascript',
        theme: 'monokai',
        lineNumbers: true,
        autoCloseBrackets: true,
        matchBrackets: true,
        indentUnit: 2,
        tabSize: 2,
        lineWrapping: true
    });

    var outputEditor = CodeMirror.fromTextArea(document.getElementById('output-editor'), {
        mode: 'javascript',
        theme: 'monokai',
        lineNumbers: true,
        readOnly: true,
        lineWrapping: true
    });

    // File input handler
    $('#js-file-input').on('change', function(e) {
        var file = e.target.files[0];
        if (file) {
            var reader = new FileReader();
            reader.onload = function(e) {
                inputEditor.setValue(e.target.result);
            };
            reader.readAsText(file);
        }
    });

    // Minify JavaScript
    $('#minify-btn').on('click', function() {
        var code = inputEditor.getValue();
        if (!code.trim()) {
            alert('Please enter some JavaScript code first.');
            return;
        }

        var minified = minifyJS(code);
        outputEditor.setValue(minified);
        updateStats(code, minified);
        enableDownloadButtons();
    });

    // Beautify JavaScript
    $('#beautify-btn').on('click', function() {
        var code = inputEditor.getValue();
        if (!code.trim()) {
            alert('Please enter some JavaScript code first.');
            return;
        }

        var beautified = beautifyJS(code);
        outputEditor.setValue(beautified);
        updateStats(code, beautified);
        enableDownloadButtons();
    });

    // Clear editors
    $('#clear-btn').on('click', function() {
        inputEditor.setValue('');
        outputEditor.setValue('');
        $('#file-stats').hide();
        disableDownloadButtons();
    });

    // Download processed JavaScript
    $('#download-btn').on('click', function() {
        var content = outputEditor.getValue();
        if (!content) return;

        var blob = new Blob([content], { type: 'application/javascript' });
        var url = URL.createObjectURL(blob);
        var a = document.createElement('a');
        a.href = url;
        a.download = 'processed.js';
        a.click();
        URL.revokeObjectURL(url);
    });

    // Copy to clipboard
    $('#copy-btn').on('click', function() {
        var content = outputEditor.getValue();
        if (!content) return;

        navigator.clipboard.writeText(content).then(function() {
            alert('Code copied to clipboard!');
        });
    });

    function minifyJS(code) {
        // Remove single-line comments (// ...)
        code = code.replace(/\/\/.*$/gm, '');

        // Remove multi-line comments (/* ... */)
        code = code.replace(/\/\*[\s\S]*?\*\//g, '');

        // Remove unnecessary whitespace
        code = code.replace(/\s+/g, ' ');

        // Remove spaces around operators and punctuation
        code = code.replace(/\s*([{}();,:])\s*/g, '$1');
        code = code.replace(/\s*([=+\-*/<>!&|])\s*/g, '$1');

        return code.trim();
    }

    function beautifyJS(code) {
        var formatted = '';
        var indentLevel = 0;
        var indentStr = '  ';
        var inString = false;
        var stringChar = '';
        var i = 0;

        while (i < code.length) {
            var char = code[i];
            var nextChar = code[i + 1] || '';

            // Handle strings
            if ((char === '"' || char === "'") && !inString) {
                inString = true;
                stringChar = char;
                formatted += char;
            } else if (char === stringChar && inString && code[i-1] !== '\\') {
                inString = false;
                stringChar = '';
                formatted += char;
            } else if (inString) {
                formatted += char;
            } else {
                // Handle formatting outside strings
                if (char === '{') {
                    formatted += char + '\n';
                    indentLevel++;
                    formatted += indentStr.repeat(indentLevel);
                } else if (char === '}') {
                    formatted = formatted.replace(/\s+$/, '');
                    indentLevel--;
                    formatted += '\n' + indentStr.repeat(indentLevel) + char;
                    if (nextChar && nextChar !== ';' && nextChar !== ',') {
                        formatted += '\n' + indentStr.repeat(indentLevel);
                    }
                } else if (char === ';') {
                    formatted += char;
                    if (nextChar !== '}') {
                        formatted += '\n' + indentStr.repeat(indentLevel);
                    }
                } else if (char === ',') {
                    formatted += char + ' ';
                } else {
                    formatted += char;
                }
            }
            i++;
        }

        return formatted;
    }

    function updateStats(original, processed) {
        var originalSize = new Blob([original]).size;
        var processedSize = new Blob([processed]).size;
        var ratio = ((originalSize - processedSize) / originalSize * 100).toFixed(1);

        $('#original-size').text(formatBytes(originalSize));
        $('#compressed-size').text(formatBytes(processedSize));
        $('#compression-ratio').text(ratio + '% reduction');
        $('#file-stats').show();
    }

    function formatBytes(bytes) {
        if (bytes === 0) return '0 bytes';
        var k = 1024;
        var sizes = ['bytes', 'KB', 'MB'];
        var i = Math.floor(Math.log(bytes) / Math.log(k));
        return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
    }

    function enableDownloadButtons() {
        $('#download-btn, #copy-btn').prop('disabled', false);
    }

    function disableDownloadButtons() {
        $('#download-btn, #copy-btn').prop('disabled', true);
    }
});
</script>

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "SoftwareApplication",
  "name": "Free Online JavaScript Compressor and Minifier",
  "applicationCategory": "DeveloperApplication",
  "operatingSystem": "Any",
  "offers": {
    "@type": "Offer",
    "price": "0",
    "priceCurrency": "USD"
  },
  "description": "Compress, minify, and beautify JavaScript code for free online. Reduce file size and optimize your JS files.",
  "keywords": "javascript, compressor, minifier, beautifier, online tool, js optimizer"
}
</script>
{%endblock%}